//
// Created by mio on 25-4-10.
//



#include "TcpSocket.h"


void SocketUtil::SetNonBlock(int sockfd)
{
    unsigned long on = 1;
    ioctlsocket(sockfd, FIONBIO, &on);
}

void SocketUtil::SetBlock(int sockfd)
{
    unsigned long on = 0;
    ioctlsocket(sockfd, FIONBIO, &on);
}

void SocketUtil::SetReuseAddr(int sockfd)
{
    int on = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
}

void SocketUtil::SetReusePort(int sockfd)
{

}

void SocketUtil::SetKeepAlive(int sockfd)
{
    int on = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char*)&on, sizeof(on));
}

void SocketUtil::SetSendBufSize(int sockfd, int size)
{
    setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&size, sizeof(size));
}

void SocketUtil::SetRecvBufSize(int sockfd, int size)
{
    setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char*)&size, sizeof(size));
}

// ----

TcpSocket::TcpSocket()
{

}

TcpSocket::~TcpSocket()
{

}

int TcpSocket::Create()
{
    sockfd_ = ::socket(AF_INET, SOCK_STREAM, 0);
    return sockfd_;
}

bool TcpSocket::Bind(std::string ip, short port)
{
    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    addr.sin_port = htons(port);
    if (::bind(sockfd_, (sockaddr*)&addr, sizeof(sockaddr)) == -1)
    {
        return false;
    }
    return true;
}

bool TcpSocket::Listen(int backlog)
{
    if (sockfd_ == -1)
        return false;
    if (::listen(sockfd_, backlog) == -1)
        return false;
    return true;
}

bool TcpSocket::Connect(std::string ip, uint16_t port, int timeout) {
    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    addr.sin_port = htons(port);
    if (::connect(sockfd_, (sockaddr*)&addr, sizeof(sockaddr)) == -1) {
        return false;
    }
    return true;
}

int TcpSocket::Accept()
{
    sockaddr_in addr = {0};
    socklen_t addrlen = sizeof(addr);
    return ::accept(sockfd_, (sockaddr*)&addr, &addrlen);
}

void TcpSocket::Close()
{
    if (sockfd_ != -1)
    {
        closesocket(sockfd_);
        sockfd_ = -1;
    }
}

void TcpSocket::ShutdownWrite()
{
    if (sockfd_ != -1)
    {
        /* 作用：
         *  - 该套接字不能再发送数据。任何后续的 send 或 write 调用会失败
         *  - 内核会向对方发送一个 FIN 包，表示本端的数据发送完毕
         *  - 该套接字仍然可以接收数据。可以继续调用 recv 或 read 来读取对方可能仍在发送的数据
         */
        shutdown(sockfd_, 1); // SHUT_WR: 一个常量，指示要关闭连接的写入方向
        sockfd_ = -1;
    }
}
